// Abstract Classes (抽象类) 示例
// 演示 Pascal 中抽象类的各种用法
program p_31_abstract_classes;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式，支持面向对象编程
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils;  // 系统工具单元，包含常用的系统函数

// 定义抽象基类：车辆
type
  TVehicle = class
  protected
    FName: String;
    FMaxSpeed: Integer;
  public
    constructor Create(const AName: String; AMaxSpeed: Integer);
    
    // 抽象方法：启动车辆
    procedure StartEngine; virtual; abstract;
    
    // 抽象方法：停止车辆
    procedure StopEngine; virtual; abstract;
    
    // 抽象方法：移动
    procedure Move; virtual; abstract;
    
    // 具体方法：显示基本信息
    procedure DisplayInfo;
    
    // 模板方法：驾驶流程（使用抽象方法）
    procedure Drive;
    
    property Name: String read FName;
    property MaxSpeed: Integer read FMaxSpeed;
  end;

// TVehicle类的实现
constructor TVehicle.Create(const AName: String; AMaxSpeed: Integer);
begin
  inherited Create;
  FName := AName;
  FMaxSpeed := AMaxSpeed;
  WriteLn('  创建车辆: ', FName);
end;

procedure TVehicle.DisplayInfo;
begin
  WriteLn('  车辆信息:');
  WriteLn('    名称: ', FName);
  WriteLn('    最大速度: ', FMaxSpeed, ' km/h');
end;

// 模板方法：定义了驾驶的基本流程
procedure TVehicle.Drive;
begin
  WriteLn('  开始驾驶车辆: ', FName);
  StartEngine;  // 调用抽象方法
  Move;         // 调用抽象方法
  StopEngine;   // 调用抽象方法
  WriteLn('  驾驶结束');
end;

// 定义派生类：汽车
type
  TCar = class(TVehicle)
  private
    FNumberOfDoors: Integer;
  public
    constructor Create(const AName: String; AMaxSpeed: Integer; ANumberOfDoors: Integer);
    
    // 实现抽象方法：启动引擎
    procedure StartEngine; override;
    
    // 实现抽象方法：停止引擎
    procedure StopEngine; override;
    
    // 实现抽象方法：移动
    procedure Move; override;
    
    // 具体方法：按喇叭
    procedure Honk;
    
    property NumberOfDoors: Integer read FNumberOfDoors;
  end;

// TCar类的实现
constructor TCar.Create(const AName: String; AMaxSpeed: Integer; ANumberOfDoors: Integer);
begin
  inherited Create(AName, AMaxSpeed);
  FNumberOfDoors := ANumberOfDoors;
  WriteLn('  创建汽车: ', FName, ', 车门数: ', FNumberOfDoors);
end;

procedure TCar.StartEngine;
begin
  WriteLn('  汽车 ', FName, ' 的内燃机启动，发出轰鸣声');
end;

procedure TCar.StopEngine;
begin
  WriteLn('  汽车 ', FName, ' 的内燃机停止');
end;

procedure TCar.Move;
begin
  WriteLn('  汽车 ', FName, ' 在道路上行驶，最高时速 ', FMaxSpeed, ' km/h');
end;

procedure TCar.Honk;
begin
  WriteLn('  汽车 ', FName, ' 按喇叭：嘀嘀！');
end;

// 定义派生类：自行车
type
  TBicycle = class(TVehicle)
  private
    FNumberOfGears: Integer;
  public
    constructor Create(const AName: String; AMaxSpeed: Integer; ANumberOfGears: Integer);
    
    // 实现抽象方法：启动（自行车不需要启动引擎）
    procedure StartEngine; override;
    
    // 实现抽象方法：停止
    procedure StopEngine; override;
    
    // 实现抽象方法：移动
    procedure Move; override;
    
    // 具体方法：响铃
    procedure RingBell;
    
    property NumberOfGears: Integer read FNumberOfGears;
  end;

// TBicycle类的实现
constructor TBicycle.Create(const AName: String; AMaxSpeed: Integer; ANumberOfGears: Integer);
begin
  inherited Create(AName, AMaxSpeed);
  FNumberOfGears := ANumberOfGears;
  WriteLn('  创建自行车: ', FName, ', 齿轮数: ', FNumberOfGears);
end;

procedure TBicycle.StartEngine;
begin
  WriteLn('  自行车 ', FName, ' 不需要启动引擎，准备骑行');
end;

procedure TBicycle.StopEngine;
begin
  WriteLn('  自行车 ', FName, ' 停止骑行');
end;

procedure TBicycle.Move;
begin
  WriteLn('  自行车 ', FName, ' 在自行车道上骑行，最高时速 ', FMaxSpeed, ' km/h');
end;

procedure TBicycle.RingBell;
begin
  WriteLn('  自行车 ', FName, ' 响铃：叮铃铃！');
end;

// 定义派生类：飞机
type
  TAirplane = class(TVehicle)
  private
    FNumberOfEngines: Integer;
  public
    constructor Create(const AName: String; AMaxSpeed: Integer; ANumberOfEngines: Integer);
    
    // 实现抽象方法：启动引擎
    procedure StartEngine; override;
    
    // 实现抽象方法：停止引擎
    procedure StopEngine; override;
    
    // 实现抽象方法：移动
    procedure Move; override;
    
    // 具体方法：起飞
    procedure TakeOff;
    
    // 具体方法：降落
    procedure Land;
    
    property NumberOfEngines: Integer read FNumberOfEngines;
  end;

// TAirplane类的实现
constructor TAirplane.Create(const AName: String; AMaxSpeed: Integer; ANumberOfEngines: Integer);
begin
  inherited Create(AName, AMaxSpeed);
  FNumberOfEngines := ANumberOfEngines;
  WriteLn('  创建飞机: ', FName, ', 引擎数: ', FNumberOfEngines);
end;

procedure TAirplane.StartEngine;
begin
  WriteLn('  飞机 ', FName, ' 启动 ', FNumberOfEngines, ' 个喷气引擎');
end;

procedure TAirplane.StopEngine;
begin
  WriteLn('  飞机 ', FName, ' 关闭所有引擎');
end;

procedure TAirplane.Move;
begin
  WriteLn('  飞机 ', FName, ' 在天空中飞行，最大速度 ', FMaxSpeed, ' km/h');
end;

procedure TAirplane.TakeOff;
begin
  WriteLn('  飞机 ', FName, ' 在跑道上加速并起飞');
end;

procedure TAirplane.Land;
begin
  WriteLn('  飞机 ', FName, ' 降落并滑行到停机坪');
end;

// 程序主入口
begin
  WriteLn('=== Pascal 抽象类示例 ===');
  WriteLn;
  
  // 注意：不能创建抽象类的实例
  // var vehicle: TVehicle := TVehicle.Create('抽象车辆', 100); // 这会导致编译错误
  
  // 1. 创建具体的派生类对象
  WriteLn('1. 创建具体的派生类对象:');
  var car: TCar := TCar.Create('丰田卡罗拉', 180, 4);
  var bicycle: TBicycle := TBicycle.Create('山地自行车', 30, 21);
  var airplane: TAirplane := TAirplane.Create('波音737', 900, 2);
  
  try
    WriteLn;
    
    // 2. 调用具体方法
    WriteLn('2. 调用具体方法:');
    car.DisplayInfo;
    WriteLn('  车门数: ', car.NumberOfDoors);
    car.Honk;
    
    WriteLn;
    bicycle.DisplayInfo;
    WriteLn('  齿轮数: ', bicycle.NumberOfGears);
    bicycle.RingBell;
    
    WriteLn;
    airplane.DisplayInfo;
    WriteLn('  引擎数: ', airplane.NumberOfEngines);
    airplane.TakeOff;
    
    WriteLn;
    
    // 3. 调用实现的抽象方法
    WriteLn('3. 调用实现的抽象方法:');
    car.StartEngine;
    car.Move;
    car.StopEngine;
    
    WriteLn;
    bicycle.StartEngine;
    bicycle.Move;
    bicycle.StopEngine;
    
    WriteLn;
    airplane.StartEngine;
    airplane.Move;
    airplane.StopEngine;
    airplane.Land;
    
    WriteLn;
    
    // 4. 多态性演示：通过基类引用操作派生类对象
    WriteLn('4. 多态性演示:');
    var vehicles: array[1..3] of TVehicle;
    
    vehicles[1] := car;
    vehicles[2] := bicycle;
    vehicles[3] := airplane;
    
    for var i := 1 to 3 do
    begin
      WriteLn('  操作车辆 ', i, ':');
      vehicles[i].DisplayInfo;
      vehicles[i].Drive;  // 调用模板方法，内部调用抽象方法
      WriteLn;
    end;
    
    WriteLn;
    
    // 5. 类型检查和转换
    WriteLn('5. 类型检查和转换:');
    var vehicle: TVehicle := car;
    
    if vehicle is TCar then
    begin
      WriteLn('  对象是汽车类型');
      TCar(vehicle).Honk;
    end;
    
    vehicle := airplane;
    if vehicle is TAirplane then
    begin
      WriteLn('  对象是飞机类型');
      TAirplane(vehicle).TakeOff;
    end;
  finally
    // 释放对象
    car.Free;
    bicycle.Free;
    airplane.Free;
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中抽象类的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.